  1 /**
  2  * @fileoverview 百度地图的可根据当前poi点来进行周边检索、公交、驾车查询的信息窗口，对外开放。
  3  * 主入口类是<a href="symbols/BMapLib.SearchInfoWindow.html">SearchInfoWindow</a>，
  4  * 基于Baidu Map API 1.4。
  5  *
  6  * @author Baidu Map Api Group
  7  * @version 1.4
  8  */
  9 /**
 10  * @namespace BMap的所有library类均放在BMapLib命名空间下
 11  */
 12 var BMapLib = window.BMapLib = BMapLib || {};
 13 //常量，searchInfoWindow可选择的检索类型
 14 var BMAPLIB_TAB_SEARCH   = 0, BMAPLIB_TAB_TO_HERE  = 1, BMAPLIB_TAB_FROM_HERE  = 2;
 15 (function() {
 16     //声明baidu包
 17     var T, baidu = T = baidu || {version: '1.5.0'};
 18     baidu.guid = '$BAIDU$';
 19     //以下方法为百度Tangram框架中的方法，请到http://tangram.baidu.com 查看文档
 20     (function() {
 21         window[baidu.guid] = window[baidu.guid] || {};
 22 
 23 		baidu.lang = baidu.lang || {};
 24         baidu.lang.isString = function (source) {
 25             return '[object String]' == Object.prototype.toString.call(source);
 26         };
 27         baidu.lang.Event = function (type, target) {
 28             this.type = type;
 29             this.returnValue = true;
 30             this.target = target || null;
 31             this.currentTarget = null;
 32         };
 33 
 34 
 35         baidu.object = baidu.object || {};
 36         baidu.extend =
 37         baidu.object.extend = function (target, source) {
 38             for (var p in source) {
 39                 if (source.hasOwnProperty(p)) {
 40                     target[p] = source[p];
 41                 }
 42             }
 43 
 44             return target;
 45         };
 46         baidu.event = baidu.event || {};
 47         baidu.event._listeners = baidu.event._listeners || [];
 48         baidu.dom = baidu.dom || {};
 49 
 50         baidu.dom._g = function (id) {
 51             if (baidu.lang.isString(id)) {
 52                 return document.getElementById(id);
 53             }
 54             return id;
 55         };
 56         baidu._g = baidu.dom._g;
 57         baidu.event.on = function (element, type, listener) {
 58             type = type.replace(/^on/i, '');
 59             element = baidu.dom._g(element);
 60             var realListener = function (ev) {
 61                     // 1. 这里不支持EventArgument,  原因是跨frame的事件挂载
 62                     // 2. element是为了修正this
 63                     listener.call(element, ev);
 64                 },
 65                 lis = baidu.event._listeners,
 66                 filter = baidu.event._eventFilter,
 67                 afterFilter,
 68                 realType = type;
 69             type = type.toLowerCase();
 70             // filter过滤
 71             if(filter && filter[type]){
 72                 afterFilter = filter[type](element, type, realListener);
 73                 realType = afterFilter.type;
 74                 realListener = afterFilter.listener;
 75             }
 76 
 77             // 事件监听器挂载
 78             if (element.addEventListener) {
 79                 element.addEventListener(realType, realListener, false);
 80             } else if (element.attachEvent) {
 81                 element.attachEvent('on' + realType, realListener);
 82             }
 83             // 将监听器存储到数组中
 84             lis[lis.length] = [element, type, listener, realListener, realType];
 85             return element;
 86         };
 87 
 88         baidu.on = baidu.event.on;
 89         baidu.event.un = function (element, type, listener) {
 90             element = baidu.dom._g(element);
 91             type = type.replace(/^on/i, '').toLowerCase();
 92 
 93             var lis = baidu.event._listeners,
 94                 len = lis.length,
 95                 isRemoveAll = !listener,
 96                 item,
 97                 realType, realListener;
 98             while (len--) {
 99                 item = lis[len];
100 
101                 if (item[1] === type
102                     && item[0] === element
103                     && (isRemoveAll || item[2] === listener)) {
104                    	realType = item[4];
105                    	realListener = item[3];
106                     if (element.removeEventListener) {
107                         element.removeEventListener(realType, realListener, false);
108                     } else if (element.detachEvent) {
109                         element.detachEvent('on' + realType, realListener);
110                     }
111                     lis.splice(len, 1);
112                 }
113             }
114 
115             return element;
116         };
117         baidu.un = baidu.event.un;
118         baidu.dom.g = function (id) {
119             if ('string' == typeof id || id instanceof String) {
120                 return document.getElementById(id);
121             } else if (id && id.nodeName && (id.nodeType == 1 || id.nodeType == 9)) {
122                 return id;
123             }
124             return null;
125         };
126         baidu.g = baidu.G = baidu.dom.g;
127         baidu.string = baidu.string || {};
128 
129         baidu.browser = baidu.browser || {};
130         baidu.browser.ie = baidu.ie = /msie (\d+\.\d+)/i.test(navigator.userAgent) ? (document.documentMode || + RegExp['\x241']) : undefined;
131         baidu.dom._NAME_ATTRS = (function () {
132             var result = {
133                 'cellpadding': 'cellPadding',
134                 'cellspacing': 'cellSpacing',
135                 'colspan': 'colSpan',
136                 'rowspan': 'rowSpan',
137                 'valign': 'vAlign',
138                 'usemap': 'useMap',
139                 'frameborder': 'frameBorder'
140             };
141 
142             if (baidu.browser.ie < 8) {
143                 result['for'] = 'htmlFor';
144                 result['class'] = 'className';
145             } else {
146                 result['htmlFor'] = 'for';
147                 result['className'] = 'class';
148             }
149 
150             return result;
151         })();
152         baidu.dom.setAttr = function (element, key, value) {
153             element = baidu.dom.g(element);
154             if ('style' == key){
155                 element.style.cssText = value;
156             } else {
157                 key = baidu.dom._NAME_ATTRS[key] || key;
158                 element.setAttribute(key, value);
159             }
160             return element;
161         };
162          baidu.setAttr = baidu.dom.setAttr;
163         baidu.dom.setAttrs = function (element, attributes) {
164             element = baidu.dom.g(element);
165             for (var key in attributes) {
166                 baidu.dom.setAttr(element, key, attributes[key]);
167             }
168             return element;
169         };
170         baidu.setAttrs = baidu.dom.setAttrs;
171         baidu.dom.create = function(tagName, opt_attributes) {
172             var el = document.createElement(tagName),
173                 attributes = opt_attributes || {};
174             return baidu.dom.setAttrs(el, attributes);
175         };
176 
177         T.undope=true;
178     })();
179 
180     /**
181      * @exports SearchInfoWindow as BMapLib.SearchInfoWindow
182      */
183 
184     var SearchInfoWindow =
185         /**
186          * SearchInfoWindow类的构造函数
187          * @class SearchInfoWindow <b>入口</b>。
188          * 可以定义检索模版。
189          * @constructor
190          * @param {Map} map Baidu map的实例对象.
191          * @param {String} content searchInfoWindow中的内容,支持HTML内容.
192          * @param {Json Object} opts 可选的输入参数，非必填项。可输入选项包括：<br />
193          * {<br />"<b>title</b>" : {String} searchInfoWindow的标题内容，支持HTML内容<br/>
194          * {<br />"<b>width</b>" : {Number} searchInfoWindow的内容宽度<br/>
195          * {<br />"<b>height</b>" : {Number} searchInfoWindow的内容高度 <br/>
196          * {<br />"<b>offset</b>" : {Size} searchInfoWindow的偏移量<br/>
197          * <br />"<b>enableAutoPan</b>" : {Boolean} 是否启动自动平移功能,默认开启    <br />
198          * <br />"<b>panel</b>" : {String} 用来展现检索信息的面板,可以是dom元素或元素的ID值 <br />
199          * <br />"<b>searchTypes</b>" : {Array} 通过传入数组设置检索面板的Tab选项共有三个选项卡可选择，选项卡顺序也按照数组的顺序来排序，传入空数组则不显示检索模版，不设置此参数则默认所有选项卡都显示。数组可传入的值为常量：BMAPLIB_TAB_SEARCH<周边检索>, BMAPLIB_TAB_TO_HERE<到去这里>, BMAPLIB_TAB_FROM_HERE<从这里出发>  <br />
200          * }<br />.
201          * @example <b>参考示例：</b><br />
202          * var searchInfoWindow = new BMapLib.SearchInfoWindow(map,"百度地图api",{
203          *     title "百度大厦",
204          *     width  : 280,
205          *     height : 50,
206          *     panel  : "panel", //检索结果面板
207          *     enableAutoPan : true, //自动平移
208          *     searchTypes :[
209          *         BMAPLIB_TAB_SEARCH,   //周边检索
210          *         BMAPLIB_TAB_TO_HERE,  //到这里去
211          *         BMAPLIB_TAB_FROM_HERE //从这里出发
212          *     ]
213          * });
214          */
215         BMapLib.SearchInfoWindow = function(map, content, opts) {
216 
217         //存储当前实例
218         this.guid = guid++;
219         BMapLib.SearchInfoWindow.instance[this.guid] = this;
220 
221         this._isOpen = false;
222         this._map = map;
223 
224         this._opts = opts   = opts || {};
225         this._content = content || "";
226         this._opts.width          =  opts.width;
227         this._opts.height         =  opts.height;
228         this._opts._title         =  opts.title || "";
229         this._opts.offset         =  opts.offset || new BMap.Size(0,0);
230         this._opts.enableAutoPan  = opts.enableAutoPan === false? false : true;
231         this._opts._panel         = opts.panel || null;
232         this._opts._searchTypes   = opts.searchTypes; //传入数组形式
233     }
234     SearchInfoWindow.prototype = new BMap.Overlay();
235     SearchInfoWindow.prototype.initialize = function(map) {
236         this._closeOtherSearchInfo();
237         var me = this;
238 
239         var div = this._createSearchTemplate();
240 
241         var floatPane = map.getPanes().floatPane;
242         floatPane.style.width = "auto";
243         floatPane.appendChild(div);
244         this._initSearchTemplate();
245         //设置完内容后，获取div的宽度,高度
246         this._getSearchInfoWindowSize();
247         this._boxWidth = parseInt(this.container.offsetWidth,10);
248         this._boxHeight = parseInt(this.container.offsetHeight,10);
249         //阻止各种冒泡事件
250         baidu.event.on(div,"onmousedown",function(e){
251             me._stopBubble(e);
252         });
253         baidu.event.on(div,"onmouseover",function(e){
254             me._stopBubble(e);
255         });
256         baidu.event.on(div,"click",function(e){
257             me._stopBubble(e);
258         });
259         baidu.event.on(div,"dblclick",function(e){
260             me._stopBubble(e);
261         });
262         return div;
263     }
264     SearchInfoWindow.prototype.draw = function() {
265         this._isOpen && this._adjustPosition(this._point);
266     }
267     /**
268      * 打开searchInfoWindow
269      * @param {Marker|Point} location 要在哪个marker或者point上打开searchInfoWindow
270      * @return none
271      *
272      * @example <b>参考示例：</b><br />
273      * searchInfoWindow.open();
274      */
275     SearchInfoWindow.prototype.open = function(anchor){
276         this._map.closeInfoWindow();
277         var me = this,poi;
278         if(!this._isOpen) {
279             this._map.addOverlay(this);
280             this._isOpen = true;
281             //延迟10ms派发open事件，使后绑定的事件可以触发。
282             setTimeout(function(){
283                 me._dispatchEvent(me,"open",{"point" : me._point});
284             },10);
285         }
286         if(anchor instanceof BMap.Point){
287             poi = anchor;
288             //清除之前存在的marker事件绑定，如果存在的话
289             this._removeMarkerEvt();
290             this._marker = null;
291         }else if(anchor instanceof BMap.Marker){
292         	//如果当前marker不为空，说明是第二个marker，或者第二次点open按钮,先移除掉之前绑定的事件
293         	if(this._marker){
294         		this._removeMarkerEvt();
295         	}
296             poi = anchor.getPosition();
297             this._marker = anchor;
298             !this._markerDragend && this._marker.addEventListener("dragend",this._markerDragend = function(e){
299             	me._point = e.point;
300             	me._adjustPosition(me._point);
301             	me._panBox();
302             	me.show();
303             });
304              //给marker绑定dragging事件，拖动marker的时候，searchInfoWindow也跟随移动
305             !this._markerDragging && this._marker.addEventListener("dragging",this._markerDragging = function(){
306             	me.hide();
307             	me._point = me._marker.getPosition();
308                 me._adjustPosition(me._point);
309             });
310         }
311         //打开的时候，将infowindow显示
312         this.show();
313         this._point = poi;
314         this._panBox();
315         this._adjustPosition(this._point);
316     }
317     /**
318      * 关闭searchInfoWindow
319      * @return none
320      *
321      * @example <b>参考示例：</b><br />
322      * searchInfoWindow.close();
323      */
324     SearchInfoWindow.prototype.close = function(){
325         if(this._isOpen){
326             this._map.removeOverlay(this);
327             this._disposeAutoComplete();
328             this._isOpen = false;
329             this._dispatchEvent(this,"close",{"point" : this._point});
330         }
331     }
332 
333 	/**
334    	 * 打开searchInfoWindow时，派发事件的接口
335      * @name SearchInfoWindow#Open
336      * @event
337      * @param {Event Object} e 回调函数会返回event参数，包括以下返回值：
338      * <br />{"<b>target</b> : {BMap.Overlay} 触发事件的元素,
339      * <br />"<b>type</b>：{String} 事件类型,
340      * <br />"<b>point</b>：{Point} searchInfoWindow的打开位置}
341      *
342      * @example <b>参考示例：</b>
343      * searchInfoWindow.addEventListener("open", function(e) {
344      *     alert(e.type);
345      * });
346      */
347    /**
348    	 * 关闭searchInfoWindow时，派发事件的接口
349      * @name SearchInfoWindow#Close
350      * @event
351      * @param {Event Object} e 回调函数会返回event参数，包括以下返回值：
352      * <br />{"<b>target</b> : {BMap.Overlay} 触发事件的元素,
353      * <br />"<b>type</b>：{String} 事件类型,
354      * <br />"<b>point</b>：{Point} searchInfoWindow的关闭位置}
355      *
356      * @example <b>参考示例：</b>
357      * searchInfoWindow.addEventListener("close", function(e) {
358      *     alert(e.type);
359      * });
360      */
361   /**
362      * 启用自动平移
363      * @return none
364      *
365      * @example <b>参考示例：</b><br />
366      * searchInfoWindow.enableAutoPan();
367      */
368     SearchInfoWindow.prototype.enableAutoPan = function(){
369         this._opts.enableAutoPan = true;
370     }
371     /**
372      * 禁用自动平移
373      * @return none
374      *
375      * @example <b>参考示例：</b><br />
376      * searchInfoWindow.disableAutoPan();
377      */
378     SearchInfoWindow.prototype.disableAutoPan = function(){
379         this._opts.enableAutoPan = false;
380     }
381     /**
382      * 设置searchInfoWindow的内容
383      * @param {String|HTMLElement} content 弹出气泡中的内容，支持HTML格式
384      * @return none
385      *
386      * @example <b>参考示例：</b><br />
387      * searchInfoWindow.setContent("百度地图API");
388      */
389     SearchInfoWindow.prototype.setContent = function(content){
390       	this._setContent(content);
391       	this._getSearchInfoWindowSize();
392         this._adjustPosition(this._point);
393     },
394     /**
395      * 设置searchInfoWindow的内容
396      * @param {String|HTMLElement} title 弹出气泡中的内容，支持HTML格式
397      * @return none
398      *
399      * @example <b>参考示例：</b><br />
400      * searchInfoWindow.setTitle("百度地图API");
401      */
402     SearchInfoWindow.prototype.setTitle = function(title){
403         this.dom.title.innerHTML = title;
404         this._opts._title = title;
405     }
406     /**
407      * 获取searchInfoWindow的内容
408      * @return {String} String
409      *
410      * @example <b>参考示例：</b><br />
411      * alret(searchInfoWindow.getContent());
412      */
413     SearchInfoWindow.prototype.getContent = function(){
414         return this.dom.content.innerHTML;
415     },
416     /**
417      * 获取searchInfoWindow的标题
418      * @return {String} String
419      *
420      * @example <b>参考示例：</b><br />
421      * alert(searchInfoWindow.getTitle());
422      */
423     SearchInfoWindow.prototype.getTitle = function(){
424         return this.dom.title.innerHTML;
425     }
426     /**
427      * 设置信息窗的地理位置
428      * @param {Point} point 设置position
429      * @return none
430      *
431      * @example <b>参考示例：</b><br />
432      * searchInfoWindow.setPosition(new BMap.Point(116.35,39.911));
433      */
434     SearchInfoWindow.prototype.setPosition = function(poi){
435         this._point = poi;
436         this._adjustPosition(poi);
437         this._panBox();
438         this._removeMarkerEvt();
439     }
440     /**
441      * 获得信息窗的地理位置
442      * @return {Point} 信息窗的地理坐标
443      *
444      * @example <b>参考示例：</b><br />
445      * searchInfoWindow.getPosition();
446      */
447     SearchInfoWindow.prototype.getPosition = function(){
448         return this._point;
449     }
450     /**
451      * 返回信息窗口的箭头距离信息窗口在地图
452      * 上所锚定的地理坐标点的像素偏移量。
453      * @return {Size} Size
454      *
455      * @example <b>参考示例：</b><br />
456      * searchInfoWindow.getOffset();
457      */
458     SearchInfoWindow.prototype.getOffset = function(){
459         return this._opts.offset;
460     },
461 
462     baidu.object.extend(SearchInfoWindow.prototype,{
463         /**
464          * 保持屏幕只有一个searchInfoWindow,关闭现在已打开的searchInfoWindow
465          */
466         _closeOtherSearchInfo: function () {
467             var instance = BMapLib.SearchInfoWindow.instance,
468                 len      = instance.length;
469             while (len--) {
470                 if (instance[len]._isOpen) {
471                     instance[len].close();
472                 }
473             }
474         },
475 
476         /**
477 	     * 设置searchInfoWindow的内容
478 	     * @param {String|HTMLElement} content 弹出气泡中的内容
479 	     * @return none
480 	     *
481 	     * @example <b>参考示例：</b><br />
482 	     * searchInfoWindow.setContent("百度地图API");
483 	     */
484         _setContent: function(content){
485 	        if(!this.dom || !this.dom.content){
486 	            return;
487 	        }
488 	        //string类型的content
489 	        if(typeof content.nodeType === "undefined"){
490 	            this.dom.content.innerHTML = content;
491 	        }else{
492 	            this.dom.content.appendChild(content);
493 	        }
494 
495             var me = this;
496             me._adjustContainerWidth();
497 
498 	        this._content = content;
499    	    },
500         /**
501          * 调整searchInfoWindow的position
502          * @return none
503          */
504         _adjustPosition: function(poi){
505             var pixel = this._getPointPosition(poi);
506             var icon = this._marker && this._marker.getIcon();
507             if(this._marker){
508                 this.container.style.bottom = -(pixel.y - this._opts.offset.height - icon.anchor.height + icon.infoWindowAnchor.height) - this._marker.getOffset().height + 2 + 30 + "px";
509                 this.container.style.left = pixel.x - icon.anchor.width + this._marker.getOffset().width + icon.infoWindowAnchor.width - this._boxWidth / 2 + 28 + "px";
510             }else{
511                 this.container.style.bottom = -(pixel.y - this._opts.offset.height) + 30 + "px";
512                 this.container.style.left = pixel.x - this._boxWidth / 2 + 25 + "px";
513             }
514         },
515         /**
516          * 得到searchInfoWindow的position
517          * @return Point  searchInfoWindow当前的position
518          */
519         _getPointPosition: function(poi){
520             this._pointPosition = this._map.pointToOverlayPixel(poi);
521             return this._pointPosition;
522         },
523         /**
524          * 得到searchInfoWindow的高度跟宽度
525          * @return none
526          */
527         _getSearchInfoWindowSize: function(){
528         	this._boxWidth = parseInt(this.container.offsetWidth,10);
529         	this._boxHeight = parseInt(this.container.offsetHeight,10);
530         },
531         /**
532          * 阻止事件冒泡
533          * @return none
534          */
535         _stopBubble: function(e){
536             if(e && e.stopPropagation){
537                 e.stopPropagation();
538             }else{
539                 window.event.cancelBubble = true;
540             }
541         },
542         /**
543          * 自动平移searchInfoWindow，使其在视野中全部显示
544          * @return none
545          */
546         _panBox: function(){
547             if(!this._opts.enableAutoPan){
548                 return;
549             }
550             var mapH = parseInt(this._map.getContainer().offsetHeight,10),
551                 mapW = parseInt(this._map.getContainer().offsetWidth,10),
552                 boxH = this._boxHeight,
553                 boxW = this._boxWidth;
554             //searchInfoWindow窗口本身的宽度或者高度超过map container
555             if(boxH >= mapH || boxW >= mapW){
556                 return;
557             }
558             //如果point不在可视区域内
559             if(!this._map.getBounds().containsPoint(this._point)){
560                 this._map.setCenter(this._point);
561             }
562             var anchorPos = this._map.pointToPixel(this._point),
563                 panTop,panY,
564                 //左侧超出
565                 panLeft  = boxW / 2 - 28 - anchorPos.x + 10,
566                 //右侧超出
567                 panRight = boxW / 2 + 28 + anchorPos.x - mapW + 10;
568             if(this._marker){
569                 var icon = this._marker.getIcon();
570             }
571 
572             //上侧超出
573             var h = this._marker ? icon.anchor.height + this._marker.getOffset().height - icon.infoWindowAnchor.height : 0;
574             panTop = boxH - anchorPos.y + this._opts.offset.height + h + 31 + 10;
575 
576             panX = panLeft > 0 ? panLeft : (panRight > 0 ? -panRight : 0);
577             panY = panTop > 0 ? panTop : 0;
578             this._map.panBy(panX,panY);
579         },
580         _removeMarkerEvt: function(){
581 			this._markerDragend && this._marker.removeEventListener("dragend", this._markerDragend);
582             this._markerDragging && this._marker.removeEventListener("dragging", this._markerDragging);
583             this._markerDragend = this._markerDragging = null;
584         },
585       	/**
586 	     * 集中派发事件函数
587 	     *
588 	     * @private
589 	     * @param {Object} instance 派发事件的实例
590 	     * @param {String} type 派发的事件名
591 	     * @param {Json} opts 派发事件里添加的参数，可选
592 	     */
593 	    _dispatchEvent: function(instance, type, opts) {
594 	        type.indexOf("on") != 0 && (type = "on" + type);
595 	        var event = new baidu.lang.Event(type);
596 	        if (!!opts) {
597 	            for (var p in opts) {
598 	                event[p] = opts[p];
599 	            }
600 	        }
601 	        instance.dispatchEvent(event);
602 	    },
603 
604         /**
605          * 检索infowindow模板的初始化操作
606          */
607         _initSearchTemplate: function() {
608             this._initDom();
609             this._initPanelTemplate();
610             this.setTitle(this._opts._title);
611             if (this._opts.height) {
612                 this.dom.content.style.height = parseInt(this._opts.height, 10) + "px";
613             }
614             this._setContent(this._content);
615             this._initService();
616             this._bind();
617             if (this._opts._searchTypes) {
618                 this._setSearchTypes();
619             }
620             this._mendIE6();
621         },
622 
623         /**
624          * 创建检索模板
625          * @return dom
626          */
627         _createSearchTemplate: function() {
628             if (!this._div) {
629                 var div = baidu.dom.create('div', {
630                     "class" : "BMapLib_SearchInfoWindow",
631                     "id"    : "BMapLib_SearchInfoWindow" + this.guid
632                 });
633                 var template = [
634                     '<div class="BMapLib_bubble_top">',
635                         '<div class="BMapLib_bubble_title" id="BMapLib_bubble_title' + this.guid + '"></div>',
636                         '<div class="BMapLib_bubble_close" id="BMapLib_bubble_close' + this.guid + '">',
637                             '<span>关闭</span>',
638                         '</div>',
639                     '</div>',
640                     '<div class="BMapLib_bubble_center">',
641                         '<div class="BMapLib_bubble_content" id="BMapLib_bubble_content' + this.guid + '">',
642                         '</div>',
643                         '<div class="BMapLib_nav" id="BMapLib_nav' + this.guid + '">',
644                             '<ul class="BMapLib_nav_tab" id="BMapLib_nav_tab' + this.guid + '">', //tab选项卡
645                                 '<li class="BMapLib_first BMapLib_current" id="BMapLib_tab_search' + this.guid + '" style="display:block;">',
646                                     '<span class="BMapLib_icon BMapLib_icon_nbs"></span>在附近找',
647                                 '</li>',
648                                 '<li class="" id="BMapLib_tab_tohere' + this.guid + '" style="display:block;">',
649                                     '<span class="BMapLib_icon BMapLib_icon_tohere"></span>到这里去',
650                                 '</li>',
651                                 '<li class="" id="BMapLib_tab_fromhere' + this.guid + '" style="display:block;">',
652                                     '<span class="BMapLib_icon BMapLib_icon_fromhere"></span>从这里出发',
653                                 '</li>',
654                             '</ul>',
655                             '<ul class="BMapLib_nav_tab_content">', //tab内容
656                                 '<li id="BMapLib_searchBox' + this.guid + '">',
657                                     '<table width="100%" align="center" border=0 cellpadding=0 cellspacing=0>',
658                                         '<tr><td style="padding-left:8px;"><input id="BMapLib_search_text' + this.guid + '" class="BMapLib_search_text" type="text" maxlength="100" autocomplete="off"></td><td width="55" style="padding-left:7px;"><input id="BMapLib_search_nb_btn' + this.guid + '" type="submit" value="搜索" class="iw_bt"></td></tr>',
659                                     '</table>',
660                                 '</li>',
661                                 '<li id="BMapLib_transBox' + this.guid + '" style="display:none">',
662                                     '<table width="100%" align="center" border=0 cellpadding=0 cellspacing=0>',
663                                         '<tr><td width="30" style="padding-left:8px;"><div id="BMapLib_stationText' + this.guid + '">起点</div></td><td><input id="BMapLib_trans_text' + this.guid + '" class="BMapLib_trans_text" type="text" maxlength="100" autocomplete="off"></td><td width="106" style="padding-left:7px;"><input id="BMapLib_search_bus_btn' + this.guid + '" type="button" value="公交" class="iw_bt" style="margin-right:5px;"><input id="BMapLib_search_drive_btn' + this.guid + '" type="button" class="iw_bt" value="驾车"></td></tr>',
664                                     '</table>',
665                                 '</li>',
666                             '</ul>',
667                         '</div>',
668                     '</div>',
669                     '<div class="BMapLib_bubble_bottom"></div>',
670                     '<img src="http://api.map.baidu.com/library/SearchInfoWindow/1.4/src/iw_tail.png" width="58" height="31" alt="" class="BMapLib_trans" id="BMapLib_trans' + this.guid + '" style="left:144px;"/>'
671                 ];
672                 div.innerHTML = template.join("");
673                 this._div = div;
674             }
675             return this._div;
676         },
677 
678         /**
679          * 创建面板
680          */
681         _initPanelTemplate: function() {
682             var panel = baidu.g(this._opts._panel);
683             if (!this.dom.panel && panel) {
684                 panel.innerHTML = "";
685                 this.dom.panel = panel;
686                 //供地址选择页用的提示文字
687                 var address = baidu.dom.create('div');
688                 address.style.cssText = "display:none;background:#FD9;height:30px;line-height:30px;text-align:center;font-size:12px;color:#994C00;";
689                 panel.appendChild(address);
690                 this.dom.panel.address = address;
691                 //供地址检索面板用
692                 var localSearch = baidu.dom.create('div');
693                 panel.appendChild(localSearch);
694                 this.dom.panel.localSearch = localSearch;
695             }
696         },
697 
698         /**
699          * 获取相关的DOM元素
700          */
701         _initDom: function () {
702             if (!this.dom) {
703                 this.dom = {
704                     container     : baidu.g("BMapLib_SearchInfoWindow" + this.guid) //容器
705                     , content     : baidu.g("BMapLib_bubble_content" + this.guid)   //主内容
706                     , title       : baidu.g("BMapLib_bubble_title" + this.guid)     //标题
707                     , closeBtn    : baidu.g("BMapLib_bubble_close" + this.guid)     //关闭按钮
708                     , transIco    : baidu.g("BMapLib_trans" + this.guid)            //infowindow底下三角形
709                     , navBox      : baidu.g("BMapLib_nav" + this.guid)              //检索容器
710                     , navTab      : baidu.g("BMapLib_nav_tab" + this.guid)          //tab容器
711                     , seartTab    : baidu.g("BMapLib_tab_search" + this.guid)       //在附近找tab
712                     , tohereTab   : baidu.g("BMapLib_tab_tohere" + this.guid)       //到这里去tab
713                     , fromhereTab : baidu.g("BMapLib_tab_fromhere" + this.guid)     //从这里出发tab
714                     , searchBox   : baidu.g("BMapLib_searchBox" + this.guid)        //普通检索容器
715                     , transBox    : baidu.g("BMapLib_transBox" + this.guid)         //公交驾车检索容器，从这里出发和到这里去公用一个容器
716                     , stationText : baidu.g("BMapLib_stationText" + this.guid)      //起点或终点文本
717                     , nbBtn       : baidu.g("BMapLib_search_nb_btn" + this.guid)    //普通检索按钮
718                     , busBtn      : baidu.g("BMapLib_search_bus_btn" + this.guid)   //公交驾车检索按钮
719                     , driveBtn    : baidu.g("BMapLib_search_drive_btn" + this.guid) //驾车检索按钮
720                     , searchText  : baidu.g("BMapLib_search_text" + this.guid)      //普通检索文本框
721                     , transText   : baidu.g("BMapLib_trans_text" + this.guid)       //公交驾车检索文本框
722                 }
723                 this.container = this.dom.container;
724             }
725         },
726 
727         /**
728          * 设置infowindow内容的宽度
729          */
730         _adjustContainerWidth: function() {
731             var width = 250,
732                 height = 0;
733             if (this._opts.width) {
734                 width = parseInt(this._opts.width, 10);
735                 width += 10;
736             } else {
737                 width = parseInt(this.dom.content.offsetWidth, 10);
738             }
739             if (width < 250) {
740                 width = 250;
741             }
742 
743             this._width = width;
744             //设置container的宽度
745             this.container.style.width = this._width + "px";
746             this._adjustTransPosition();
747         },
748 
749         /**
750          * 调整infowindow下三角形的位置
751          */
752         _adjustTransPosition: function() {
753             //调整三角形的位置
754             this.dom.transIco.style.left = this.container.offsetWidth / 2 - 2 - 29 + "px";
755             this.dom.transIco.style.top = this.container.offsetHeight - 2 + "px";
756         },
757 
758         /**
759          * 初始化各检索服务
760          */
761         _initService: function () {
762             var map  = this._map;
763             var me = this;
764             var renderOptions = {}
765             renderOptions.map = map;
766 
767             if (this.dom.panel) {
768                 renderOptions.panel = this.dom.panel.localSearch;
769             }
770 
771             if (!this.localSearch) {
772                 this.localSearch = new BMap.LocalSearch(map, {
773                     renderOptions: renderOptions
774                     , onSearchComplete : function (result) {
775                         me._clearAddress();
776                         me._drawCircleBound();
777                     }
778                 });
779             }
780 
781             if (!this.transitRoute) {
782                 this.transitRoute = new BMap.TransitRoute(map, {
783                     renderOptions: renderOptions
784                     , onSearchComplete : function (results) {
785                         me._transitRouteComplete(me.transitRoute, results);
786                     }
787                 });
788             }
789 
790             if (!this.drivingRoute) {
791                 this.drivingRoute  = new BMap.DrivingRoute(map, {
792                     renderOptions: renderOptions
793                     , onSearchComplete : function (results) {
794                         me._transitRouteComplete(me.drivingRoute, results);
795                     }
796                 });
797             }
798         },
799 
800         /**
801          * 绑定事件
802          */
803         _bind: function () {
804             var me  = this;
805 
806             //关闭按钮
807             baidu.on(this.dom.closeBtn, "click", function(e) {
808                 me.close();
809             });
810 
811             //周边检索tab键
812             baidu.on(this.dom.seartTab, "click", function(e) {
813                 me._showTabContent(BMAPLIB_TAB_SEARCH);
814             });
815 
816             //到这里去tab
817             baidu.on(this.dom.tohereTab, "click", function(e) {
818                 me._showTabContent(BMAPLIB_TAB_TO_HERE);
819             });
820 
821             //从这里出发tab
822             baidu.on(this.dom.fromhereTab, "click", function(e) {
823                 me._showTabContent(BMAPLIB_TAB_FROM_HERE);
824             });
825 
826             //周边检索按钮
827             baidu.on(this.dom.nbBtn, "click", function(e) {
828                 me._localSearchAction();
829             });
830 
831             //公交检索按钮
832             baidu.on(this.dom.busBtn, "click", function(e) {
833                 me._transitRouteAction(me.transitRoute);
834             });
835 
836             //驾车检索按钮
837             baidu.on(this.dom.driveBtn, "click", function(e) {
838                 me._transitRouteAction(me.drivingRoute);
839             });
840 
841             //文本框自动完成提示
842             this._autoCompleteIni();
843         },
844 
845         /**
846          * 显示tab内容
847          */
848         _showTabContent: function(type) {
849             this._hideAutoComplete();
850             var tabs = this.dom.navTab.getElementsByTagName("li"),
851                 len = tabs.length;
852             
853             for (var i = 0, len = tabs.length; i < len; i++) {
854                 tabs[i].className = "";
855             }
856 
857             //显示当前tab content并高亮tab
858             switch (type) {
859                 case BMAPLIB_TAB_SEARCH:
860                     this.dom.seartTab.className      = "BMapLib_current";
861                     this.dom.searchBox.style.display = "block";
862                     this.dom.transBox.style.display  = "none";
863                     break;
864                 case BMAPLIB_TAB_TO_HERE:
865                     this.dom.tohereTab.className     = "BMapLib_current";
866                     this.dom.searchBox.style.display = "none";
867                     this.dom.transBox.style.display  = "block";
868                     this.dom.stationText.innerHTML   = "起点";
869                     this._pointType = "endPoint";
870                     break;
871                 case BMAPLIB_TAB_FROM_HERE:
872                     this.dom.fromhereTab.className   = "BMapLib_current";
873                     this.dom.searchBox.style.display = "none";
874                     this.dom.transBox.style.display  = "block";
875                     this.dom.stationText.innerHTML   = "终点";
876                     this._pointType = "startPoint";
877                     break;
878             }
879 
880             this._firstTab.className += " BMapLib_first";
881         },
882 
883         /**
884          * 绑定自动完成事件
885          */
886         _autoCompleteIni: function () {
887             this.searchAC= new BMap.Autocomplete({
888                 "input"      : this.dom.searchText
889                 , "location" : this._map
890             });
891             this.transAC = new BMap.Autocomplete({
892                 "input"      : this.dom.transText
893                 , "location" : this._map
894             });
895         },
896 
897         /**
898          * 关闭autocomplete
899          */
900         _hideAutoComplete: function () {
901             this.searchAC.hide();
902             this.transAC.hide();
903         },
904 
905         /**
906          * 销毁autoComplete对象
907          */
908         _disposeAutoComplete: function() {
909             this.searchAC.dispose();
910             this.transAC.dispose();
911         },
912 
913         /**
914          * 触发localsearch事件
915          */
916         _localSearchAction: function() {
917             var kw = this._kw = this.dom.searchText.value;
918             if (kw == "") {
919                 //检测是否为空
920                 this.dom.searchText.focus();
921             } else{
922                 this._reset();
923                 this.close();
924                 var radius  = this._radius = 1000;
925                 this.localSearch.searchNearby(kw, this._point, radius);
926             }
927         },
928 
929         /**
930          * 画周边检索的圆形圈
931          */
932         _drawCircleBound: function() {
933             this._closeCircleBound();
934             var circle = this._searchCircle = new BMap.Circle(this._point, this._radius, {
935                 strokeWeight: 3,
936                 strokeOpacity: 0.4,
937                 strokeColor: "#e00",
938                 filColor: "#00e",
939                 fillOpacity:0.4
940             });
941 
942             var label = this._searchLabel = new BMap.Label('<div onmousedown ="BMapLib.SearchInfoWindow.instance[' + this.guid + ']._stopBubble()"><input type="text" value="' + this._radius + '" style="width:30px;" id="BMapLib_search_radius' + this.guid + '"/>m <a href="javascript:void(0)" title="修改" onclick="BMapLib.SearchInfoWindow.instance[' + this.guid + ']._changeSearchRadius()" style="text-decoration:none;color:blue;">修改</a><img src="http://api.map.baidu.com/images/iw_close1d3.gif" alt="关闭" title="关闭" style="cursor:pointer;padding:0 5px;" onclick="BMapLib.SearchInfoWindow.instance[' + this.guid + ']._closeCircleBound()"/></div>',{
943                 position: this._point
944             });
945 
946             this._map.addOverlay(circle);
947             this._map.addOverlay(label);
948             this._hasCircle = true;
949         },
950 
951         /**
952          * 修改周边检索的半径
953          */
954         _changeSearchRadius: function() {
955             var radius = parseInt(baidu.g("BMapLib_search_radius" + this.guid).value, 10);
956             if (radius > 0 && radius != this._radius) {
957                 this._radius = radius;
958                 this.localSearch.searchNearby(this._kw, this._point, radius);
959                 this._closeCircleBound();
960             }
961         },
962 
963         /**
964          * 关闭周边检索的圆形圈
965          */
966         _closeCircleBound: function(radius) {
967             if (this._searchCircle) {
968                 this._map.removeOverlay(this._searchCircle);
969             }
970             if (this._searchLabel) {
971                 this._map.removeOverlay(this._searchLabel);
972             }
973             this._hasCircle = false;
974         },
975 
976         /**
977          * 公交驾车检索查询
978          */
979         _transitRouteAction: function (transitDrive) {
980             var kw = this.dom.transText.value;
981             if (kw == "") {
982                 //检测是否为空
983                 this.dom.transText.focus();
984             } else {
985                 this._reset();
986                 this.close();
987                 var transPoi = this._getTransPoi(kw);
988                 transitDrive.search(transPoi.start, transPoi.end);
989             }
990         },
991 
992         /**
993          * 公交驾车查询结束操作
994          */
995         _transitRouteComplete: function(transitDrive, results) {
996             this._clearAddress();
997             var status = transitDrive.getStatus();
998             //导航结果未知的情况
999             if (status == BMAP_STATUS_UNKNOWN_ROUTE) {
1000                 var startStatus = results.getStartStatus(),
1001                     endStatus   = results.getEndStatus(),
1002                     tip         = "";
1003                 tip = "找不到相关的线路";
1004                 if (startStatus == BMAP_ROUTE_STATUS_EMPTY && endStatus == BMAP_ROUTE_STATUS_EMPTY) {
1005                     tip = "找不到相关的起点和终点";
1006                 } else {
1007                     if (startStatus == BMAP_ROUTE_STATUS_EMPTY) {
1008                         tip = "找不到相关的起点";
1009                     }
1010                     if (endStatus == BMAP_ROUTE_STATUS_EMPTY) {
1011                         tip = "找不到相关的终点";
1012                     }
1013                 }
1014                 //当前搜索的点找不到明确的路线，但是可以检索到poi点
1015                 if (this._pointType == "startPoint" && endStatus == BMAP_ROUTE_STATUS_ADDRESS || this._pointType == "endPoint" && startStatus == BMAP_ROUTE_STATUS_ADDRESS) {
1016                     this._searchAddress(transitDrive);
1017                 } else {
1018                     this.dom.panel.address.style.display = "block";
1019                     this.dom.panel.address.innerHTML = tip;
1020                 }
1021             }
1022 
1023         },
1024 
1025         /**
1026          * 检索起点或终点的可选地址
1027          */
1028         _searchAddress: function(transitDrive) {
1029             var me = this;
1030             var panel = this.dom.panel;
1031             if (!this.lsAddress) {
1032                 var renderOptions = {map: this._map};
1033                 if (panel) {
1034                     renderOptions.panel = this.dom.panel.localSearch;
1035                 }
1036                 this.lsAddress = new BMap.LocalSearch(map, {renderOptions: renderOptions});
1037             }
1038             var station = me._pointType == "startPoint" ? "终点" : "起点";
1039             if (panel) {
1040                 this.dom.panel.address.style.display = "block";
1041                 this.dom.panel.address.innerHTML = "请选择准确的" + station;
1042             }
1043             this.lsAddress.setInfoHtmlSetCallback(function(poi,html){
1044                 var button = document.createElement('div'); 
1045                 button.style.cssText="position:relative;left:50%;margin:5px 0 0 -30px;width:60px;height:27px;line-height:27px;border:1px solid #E0C3A6;text-align:center;color:#B35900;cursor:pointer;background-color:#FFEECC;border-radius:2px; background-image: -webkit-gradient(linear, left top, left bottom, from(#FFFDF8), to(#FFEECC))";
1046                 button.innerHTML = '设为' + station;
1047                 html.appendChild(button);
1048                 baidu.on(button, "click", function(){
1049                     me._clearAddress();
1050                     var nowPoint = poi.marker.getPosition();
1051                     if (station  == "起点") {
1052                         transitDrive.search(nowPoint, me._point);
1053                     } else {
1054                         transitDrive.search(me._point, nowPoint);
1055                     }
1056                 });
1057             });
1058             this._reset();
1059             this.lsAddress.search(this.dom.transText.value);
1060         },
1061 
1062         /**
1063          * 获取公交驾车的起终点
1064          */
1065         _getTransPoi: function(kw) {
1066             var start, end;
1067 
1068             if (this._pointType == "startPoint") {
1069                 start = this._point;
1070                 end   = kw;
1071             } else {
1072                 start = kw;
1073                 end   = this._point;
1074             }
1075 
1076             return {
1077                 "start" : start,
1078                 "end"   : end
1079             }
1080         },
1081 
1082         /**
1083          * 设置当前可提供的检索类型
1084          */
1085         _setSearchTypes: function () {
1086             var searchTypes = this._unique(this._opts._searchTypes),
1087                 navTab      = this.dom.navTab,
1088                 tabs        = [this.dom.seartTab, this.dom.tohereTab, this.dom.fromhereTab],
1089                 i           = 0,
1090                 len         = 0,
1091                 curIndex    = 0,
1092                 tab;
1093 
1094             this.tabLength = searchTypes.length;
1095             tabWidth = Math.floor((this._width - this.tabLength + 1) / this.tabLength);
1096             if (searchTypes.length == 0) {
1097                 //若为空则不显示检索面板
1098                 this.dom.navBox.style.display = "none";
1099             } else {
1100                 for (i = 0, len = tabs.length; i < len; i++) {
1101                     tabs[i].className = "";
1102                     tabs[i].style.display = "none";
1103                 }
1104 
1105                 for (i = 0; i < this.tabLength; i++) {
1106                     tab = tabs[searchTypes[i]];
1107                     if (i == 0) {
1108                         tab.className = "BMapLib_first BMapLib_current";
1109                         this._firstTab = tab;
1110                         curIndex = searchTypes[i];
1111                     } 
1112                     if (i == this.tabLength - 1) {
1113                         //最后一个tab的宽度
1114                         var lastWidth  = this._width - (this.tabLength - 1) * (tabWidth + 1);
1115                         if (baidu.browser.ie == 6) {
1116                             tab.style.width = lastWidth - 3 + "px";
1117                         } else {
1118                             tab.style.width = lastWidth + "px";
1119                         }
1120                     } else {
1121                         tab.style.width = tabWidth + "px";
1122                     }
1123                     tab.style.display = "block";
1124                 }
1125 
1126                 //按照数组顺序排序tab
1127                 if (searchTypes[1] != undefined) {
1128                     navTab.appendChild(tabs[searchTypes[1]])
1129                 }
1130                 if (searchTypes[2] != undefined) {
1131                     navTab.appendChild(tabs[searchTypes[2]])
1132                 }
1133                 this._showTabContent(curIndex);
1134             }
1135             this._adjustTransPosition();
1136         },
1137 
1138         /**
1139          * 对用户提供的检索类型去重，并剔除无效的结果
1140          */
1141         _unique : function (arr) {
1142             var len = arr.length, 
1143                 result = arr.slice(0), 
1144                 i, 
1145                 datum;
1146             // 从后往前双重循环比较
1147             // 如果两个元素相同，删除后一个
1148             while (--len >= 0) { 
1149                 datum = result[len]; 
1150                 if (datum < 0 || datum > 2) {
1151                     result.splice(len, 1); 
1152                     continue;
1153                 }
1154                 i = len;
1155                 while (i--) {
1156                     if (datum == result[i]) { 
1157                         result.splice(len, 1); 
1158                         break; 
1159                     } 
1160                 } 
1161             }
1162             return result;
1163         },
1164 
1165         /**
1166          * 清除最近的结果
1167          */
1168         _reset : function () {
1169             this.localSearch.clearResults();
1170             this.transitRoute.clearResults();
1171             this.drivingRoute.clearResults();
1172             this._closeCircleBound();
1173             this._hideAutoComplete();
1174         },
1175 
1176         /**
1177          * 清除地址选择页结果
1178          */
1179         _clearAddress: function() {
1180             if (this.lsAddress) {
1181                 this.lsAddress.clearResults();
1182             }
1183             if (this.dom.panel) {
1184                 this.dom.panel.address.style.display = "none";
1185             }
1186         },
1187 
1188         /**
1189           * IE6下处理PNG半透明
1190           * @param {Object} infoWin
1191           */
1192         _mendIE6 : function(infoWin){
1193             if(!baidu.browser.ie || baidu.browser.ie > 6){
1194                 return;
1195             }
1196             var popImg = this.container.getElementsByTagName("IMG");
1197             for(var i = 0; i < popImg.length; i++) {
1198                 if (popImg[i].src.indexOf('.png') < 0) {
1199                     continue;
1200                 }
1201                 popImg[i].style.cssText += ';FILTER: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='+ popImg[i].src +',sizingMethod=crop)'
1202                 popImg[i].src = "http://api.map.baidu.com/images/blank.gif";
1203             }
1204         }
1205     });
1206 
1207     //用来存储创建出来的实例
1208     var guid = 0;
1209     BMapLib.SearchInfoWindow.instance = [];
1210 
1211 })();
1212 